package com.winsdom.service.customer.impl;

import com.winsdom.entity.customer.CustomerIndividualUpdateRequest;
import com.winsdom.mapper.customer.CustomerIndividualUpdateMapper;
import com.winsdom.service.customer.CustomerIndividualUpdateService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.LinkedHashSet;

/**
 * 个体工商户客户信息更新服务实现类
 * <p>
 * 负责处理个体工商户客户信息的更新业务逻辑，包括：
 * 1. 客户类型校验（强制为个体工商户）
 * 2. 客户主表及扩展表字段更新（仅更新有变动的字段）
 * 3. 经营地址和营业执照的强制更新（覆盖式操作）
 * 4. 联系人信息的全量更新（先删除旧数据，再插入新数据）
 * <p>
 * 所有操作通过@Transactional注解保证事务一致性，
 * 若中途出现异常将自动回滚，确保数据完整性。
 */
@Service
@Transactional
public class CustomerIndividualUpdateServiceImpl implements CustomerIndividualUpdateService {
    @Resource
    private CustomerIndividualUpdateMapper mapper;

    /**
     * 更新个体工商户客户信息的完整业务流程
     * <p>
     * 执行顺序：
     * 1. 校验客户类型是否为个体工商户（类型码2），否则抛出异常
     * 2. 查询客户现有数据（用于对比字段变更）
     * 3. 更新客户主表中发生变更的字段
     * 4. 更新个体户扩展表中发生变更的字段
     * 5. 强制更新经营地址（无论是否存在，有则更新，无则忽略）
     * 6. 强制更新营业执照信息（同上）
     * 7. 全量更新联系人及楼盘关联（先删除旧数据，再插入去重后的新数据）
     *
     * @param request 个体工商户更新请求实体，包含更新后的客户信息
     * @throws IllegalArgumentException 当客户类型不为个体工商户时抛出
     */
    @Override
    public void update(CustomerIndividualUpdateRequest request) {
        // 1. 校验客户类型（业务规则：仅允许更新个体工商户类型）
        if (!request.getCustomerType().equals(2)) {
            throw new IllegalArgumentException("客户类型必须为个体户（类型码：2），当前类型码：" + request.getCustomerType());
        }

        // 2. 查询客户现有数据（用于字段变更对比）
        Map<String, Object> oldData = mapper.selectCustomerData(request.getCustomerId());
        if (oldData.isEmpty()) {
            throw new IllegalArgumentException("未找到客户ID：" + request.getCustomerId() + " 的记录");
        }

        // 3. 更新客户主表字段（仅更新有变更的字段）
        updateCustomerMainFields(request, oldData);

        // 4. 更新个体户扩展表字段（仅更新有变更的字段）
        updateIndividualBusinessFields(request, oldData);

        // 5. 强制更新经营地址（覆盖式更新，无记录则不操作）
        updateBusinessAddress(request);

        // 6. 强制更新营业执照信息（覆盖式更新，无记录则不操作）
        updateBusinessLicense(request);

        // 7. 处理联系人及楼盘关联（全量更新，先删除旧数据再插入新数据）
        processContactsAndProperties(request);
    }

    /**
     * 更新客户主表中发生变更的字段
     * <p>
     * 对比请求数据与现有数据，仅当字段值发生变化时执行更新
     *
     * @param request  更新请求对象，包含新数据
     * @param oldData  客户现有数据（从数据库查询）
     */
    private void updateCustomerMainFields(CustomerIndividualUpdateRequest request, Map<String, Object> oldData) {
        boolean isUpdateNeeded = false;
        // 客户名称
        isUpdateNeeded |= isFieldModified(oldData, "customerName", request.getCustomerName());
        // 手机号码
        isUpdateNeeded |= isFieldModified(oldData, "mobilePhone", request.getMobilePhone());
        // 电子邮箱
        isUpdateNeeded |= isFieldModified(oldData, "email", request.getEmail());

        if (isUpdateNeeded) {
            mapper.updateCustomerMain(request);
            // 记录日志（示例中省略，实际开发中可添加日志）
            System.out.println("客户主表字段更新，客户ID：" + request.getCustomerId());
        }
    }

    /**
     * 更新个体户扩展表中发生变更的字段
     * <p>
     * 对比请求数据与现有数据，仅当字段值发生变化时执行更新
     *
     * @param request  更新请求对象，包含新数据
     * @param oldData  客户现有数据（从数据库查询）
     */
    private void updateIndividualBusinessFields(CustomerIndividualUpdateRequest request, Map<String, Object> oldData) {
        boolean isUpdateNeeded = false;
        // 统一社会信用代码
        isUpdateNeeded |= isFieldModified(oldData, "registrationNumber", request.getRegistrationNumber());
        // 开户行名称
        isUpdateNeeded |= isFieldModified(oldData, "bankName", request.getBankName());
        // 银行账号
        isUpdateNeeded |= isFieldModified(oldData, "bankAccount", request.getBankAccount());

        if (isUpdateNeeded) {
            mapper.updateIndividualBusiness(request);
            // 记录日志（示例中省略，实际开发中可添加日志）
            System.out.println("个体户扩展表字段更新，客户ID：" + request.getCustomerId());
        }
    }

    /**
     * 强制更新经营地址信息（覆盖式更新）
     * <p>
     * 无论数据库中是否存在地址记录，直接调用强制更新方法，
     * 若存在则更新，若不存在则不执行插入（由Mapper实现具体逻辑）
     *
     * @param request 更新请求对象，包含新的经营地址信息
     */
    private void updateBusinessAddress(CustomerIndividualUpdateRequest request) {
        mapper.forceUpdateBusinessAddress(request);
        // 记录日志（示例中省略，实际开发中可添加日志）
        System.out.println("经营地址强制更新，客户ID：" + request.getCustomerId());
    }

    /**
     * 强制更新营业执照信息（覆盖式更新）
     * <p>
     * 无论数据库中是否存在营业执照记录，直接调用强制更新方法，
     * 若存在则更新路径，若不存在则不执行插入（由Mapper实现具体逻辑）
     *
     * @param request 更新请求对象，包含新的营业执照图片路径
     */
    private void updateBusinessLicense(CustomerIndividualUpdateRequest request) {
        mapper.forceUpdateBusinessLicense(request);
        // 记录日志（示例中省略，实际开发中可添加日志）
        System.out.println("营业执照强制更新，客户ID：" + request.getCustomerId());
    }

    /**
     * 全量更新联系人及楼盘分类关联关系
     * <p>
     * 逻辑说明：
     * 1. 先删除该客户的所有旧联系人及关联记录（物理删除）
     * 2. 遍历新联系人列表，插入新的联系人信息
     * 3. 对每个联系人的楼盘名称列表进行去重（保持顺序）
     * 4. 根据去重后的楼盘名称查询分类ID，插入关联关系
     *
     * @param request 更新请求对象，包含新的联系人信息
     */
    private void processContactsAndProperties(CustomerIndividualUpdateRequest request) {
        Long customerId = request.getCustomerId();
        // 1. 删除旧联系人及关联（级联删除）
        mapper.deleteOldContacts(customerId);

        // 2. 处理新联系人（若有）
        if (request.getContactInfos() != null) {
            for (CustomerIndividualUpdateRequest.ContactInfo contact : request.getContactInfos()) {
                // 设置客户ID关联
                contact.setCustomerId(customerId);
                // 插入新联系人
                mapper.insertContact(contact);
                Long contactId = contact.getContactId();

                // 3. 对楼盘名称去重（使用LinkedHashSet保持顺序）
                Set<String> uniqueProperties = new LinkedHashSet<>(contact.getReceiveProperties());

                // 4. 插入去重后的楼盘关联
                uniqueProperties.forEach(propertyName -> {
                    Long categoryId = mapper.selectCategoryIdByName(propertyName);
                    if (categoryId != null) {
                        mapper.insertContactProperty(contactId, categoryId);
                        System.out.println("成功关联联系人ID " + contactId + " 与楼盘分类ID " + categoryId);
                    } else {
                        System.out.println("警告：未找到楼盘名称 [" + propertyName + "] 对应的分类ID，跳过关联");
                    }
                });
            }
        }
    }

    /**
     * 判断字段值是否发生变更
     *
     * @param oldData   旧数据Map（键为字段名，值为旧值）
     * @param field     字段名（如"customerName"）
     * @param newValue  新值
     * @return 若新值不为null且与旧值不同，则返回true，否则返回false
     */
    private boolean isFieldModified(Map<String, Object> oldData, String field, Object newValue) {
        Object oldValue = oldData.get(field);
        // 对比逻辑：新值非空且与旧值不相等（使用Objects.equals处理null安全）
        return newValue != null && !Objects.equals(oldValue, newValue);
    }
}